/*******************************************************************************
* Copyright 2014 Miami-Dade County
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.sharegov.cirm.services;
import static org.sharegov.cirm.OWL.dataProperty;
import static org.sharegov.cirm.OWL.individual;
import static org.sharegov.cirm.OWL.objectProperties;
import static org.sharegov.cirm.OWL.objectProperty;
import static org.sharegov.cirm.OWL.ontology;
import static org.sharegov.cirm.OWL.owlClass;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathException;
import javax.xml.xpath.XPathFactory;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLNamedIndividual;
import org.semanticweb.owlapi.reasoner.NodeSet;
import org.sharegov.cirm.OWL;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
/**
*
* Class to call a web service based on ontology configuration.
*
* @author SABBAS
*
*/
public class OWLWebServiceCall
{
private OWLNamedIndividual service;
private OWLLiteral wsdl;
private OWLLiteral portName;
private OWLLiteral namespace;
private OWLLiteral serviceName;
private OWLLiteral endpoint;
private OWLLiteral soapAction;
private OWLLiteral username;
private OWLLiteral password;
private ArgumentMap argumentMap;
public OWLWebServiceCall(OWLNamedIndividual service)
{
this.service = service;
this.wsdl = dataProperty(service, "Wsdl");
this.portName = dataProperty(service, "PortName");
this.namespace = dataProperty(service, "Namespace");
this.serviceName = dataProperty(service, "ServiceName");
this.endpoint = dataProperty(service, "Endpoint");
this.soapAction = dataProperty(service, "SOAPAction");
this.username = dataProperty(service, "hasUsername");
this.password = dataProperty(service, "hasPassword");
this.argumentMap = new ArgumentMap(getArgumentMapping());
}
public OWLLiteral[] execute(OWLLiteral[] values) throws Exception
{
Set<OWLNamedIndividual> inputs = objectProperties(service, "hasInput");
Set<OWLNamedIndividual> outputs = objectProperties(service, "hasOutput");
argumentMap.setValuesArray(values);
// if (values.length != argumentMap.size())
// throw new Exception(
// "Pass a values array equal to the size of the configured arguments. See ontology argument mapping.");
invoke(wsdl.getLiteral(), namespace.getLiteral(), serviceName
.getLiteral(), portName.getLiteral(), endpoint.getLiteral(),
soapAction.getLiteral(), inputs, outputs, argumentMap);
return argumentMap.getValuesArray();
}
private void invoke(String wsdlLocation, String namespace,
String serviceName, String portName, String endpoint,
String soapAction, Set<OWLNamedIndividual> inputs,
Set<OWLNamedIndividual> outputs, ArgumentMap argMap) throws Exception
{
QName svc = new QName(namespace, serviceName);
QName port = new QName(namespace, portName);
Service service = Service.create(new URL(wsdlLocation), svc);
Dispatch<SOAPMessage> dispatch = service.createDispatch(port,
SOAPMessage.class, Service.Mode.MESSAGE);
BindingProvider bp = (BindingProvider) dispatch;
if (endpoint != null)
bp.getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
if(soapAction != null)
{
bp.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
bp.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapAction);
}
if(username != null && password !=null)
{
bp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username.getLiteral());
bp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, password.getLiteral());
}
MessageFactory factory = ((SOAPBinding) bp.getBinding())
.getMessageFactory();
SOAPMessage request = factory.createMessage();
SOAPHeader header = request.getSOAPHeader();
SOAPBody body = request.getSOAPBody();
Document req = createRequest(namespace);
addInputs(req, inputs, argMap);
body.addDocument(req);
write(req);
SOAPMessage reply = null;
try
{
reply = dispatch.invoke(request);
}
catch (WebServiceException e)
{
throw e;
}
try
{
body = reply.getSOAPBody();
Document resp = body.extractContentAsDocument();
// write(resp);
getOutputs(resp, outputs, argMap);
}
catch (SOAPException e)
{
throw e;
}
}
private void write(Document resp)
{
TransformerFactory tFactory = TransformerFactory.newInstance();
try
{
Transformer transformer = tFactory.newTransformer();
DOMSource source = new DOMSource(resp);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private Document createRequest(String namespace)
throws ParserConfigurationException, IOException, SAXException
{
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.newDocument();
doc.setDocumentURI(namespace);
return doc;
}
private void addInputs(Document req, Set<OWLNamedIndividual> inputs,
ArgumentMap argMap)
{
for (OWLNamedIndividual input : inputs)
{
putInputNode(req, dataProperty(input, "XPathExpression")
.getLiteral(), argMap.get(input).getLiteral());
}
}
private void getOutputs(Document req, Set<OWLNamedIndividual> outputs,
ArgumentMap argMap)
{
for (OWLNamedIndividual output : outputs)
{
try
{
Node node = getOutputNode(req, dataProperty(output,
"XPathExpression").getLiteral());
String value = "";
if (node.getNodeType() == Node.ATTRIBUTE_NODE)
value = node.getNodeValue();
else if (node.getNodeType() == Node.ENTITY_NODE)
value = node.getTextContent();
else
value = node.getTextContent();
argMap.put(output, value);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
private Document addElement(Document doc, String xpath, String text)
{
Node parentNode = doc.getFirstChild();
if (doc != null && xpath != null && xpath.length() > 0)
{
String[] tokens = xpath.split("/");
String exp = "";
for (int i = 0; i < tokens.length; i++)
{
if (tokens[i] == null || tokens[i].isEmpty())
continue;
exp += "/" + tokens[i];
Node childNode = null;
try
{
childNode = findNode(doc, exp);
}
catch (XPathException xpe)
{
}
if (childNode == null)
childNode = doc.createElementNS(doc.getDocumentURI(),
tokens[i]);
if (parentNode == null)
{
doc.appendChild(childNode);
}
else
{
parentNode.appendChild(childNode);
}
parentNode = childNode;
}
}
parentNode.setTextContent(text);
return doc;
}
private Node findNode(final Document doc, String xpath) throws XPathException
{
NamespaceContext defaultDocContext = new NamespaceContext(){
@Override
public String getNamespaceURI(String prefix)
{
String namespace = doc.getNamespaceURI();
if (namespace == null)
namespace = doc.getFirstChild().getNamespaceURI();
return namespace;
}
@Override
public String getPrefix(String namespaceURI){return "";}
@Override
public Iterator getPrefixes(String namespaceURI){return null;}
};
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
xPath.setNamespaceContext(defaultDocContext);
return (Node) xPath.evaluate(xpath, doc, XPathConstants.NODE);
}
private void putInputNode(Document request, String xpath, String value)
{
addElement(request, xpath, value);
}
private Node getOutputNode(Document response, String xpath)
throws XPathException
{
return findNode(response, xpath);
}
private Set<OWLNamedIndividual> getArgumentMapping()
{
OWLDataFactory df = OWL.dataFactory();
OWLClassExpression paramsQuery = df.getOWLObjectIntersectionOf(
owlClass("WebArgumentMapping"), df.getOWLObjectHasValue(
objectProperty("forWebService"), service));
NodeSet<OWLNamedIndividual> S = OWL.reasoner(
ontology()).getInstances(paramsQuery, false);
OWLNamedIndividual argumentMapping = (OWLNamedIndividual) S.iterator().next()
.getEntities().iterator().next();
Set<OWLNamedIndividual> arguments = objectProperties(argumentMapping,
"hasArgument");
return arguments;
}
/**
* Class that maps a set of owl WebArgument(s) to an array of arg values.
*
* @author SABBAS
*
*/
class ArgumentMap
{
private Set<OWLNamedIndividual> argMap;
private OWLLiteral[] valuesArray;
public ArgumentMap(Set<OWLNamedIndividual> argMap)
{
this.argMap = argMap;
this.valuesArray = makeValuesArray();
}
public void setValuesArray(OWLLiteral[] valuesArray)
{
for (int i = 0; i < valuesArray.length; i++)
{
try
{
this.valuesArray[i] = valuesArray[i];
}
catch (ArrayIndexOutOfBoundsException e)
{
}
}
}
public Set<OWLNamedIndividual> getArgMap()
{
return argMap;
}
public OWLLiteral[] getValuesArray()
{
return valuesArray;
}
public OWLLiteral get(OWLNamedIndividual parameter)
{
try
{
OWLNamedIndividual argument = mappingForParameter(parameter);
int index = dataProperty(argument, "ArgumentIndex")
.parseInteger();
return valuesArray[index];
}
catch (Exception e)
{
return null;
}
}
public void put(OWLNamedIndividual parameter, String value)
{
try
{
OWLNamedIndividual argument = mappingForParameter(parameter);
int index = dataProperty(argument, "ArgumentIndex")
.parseInteger();
valuesArray[index] = OWL.dataFactory().getOWLLiteral(value);
}
catch (Exception e)
{
}
}
public int size()
{
return argMap != null ? argMap.size() : 0;
}
private OWLNamedIndividual mappingForParameter(OWLNamedIndividual parameter)
{
for (OWLNamedIndividual a : argMap)
{
if (objectProperty(a, "parameter").equals(parameter))
return a;
}
return null;
}
private OWLLiteral[] makeValuesArray()
{
OWLLiteral[] result = new OWLLiteral[argMap.size()];
int i = 0;
for (OWLNamedIndividual a : argMap)
{
OWLLiteral dataType = dataProperty(objectProperty(a,
"parameter").asOWLNamedIndividual(), "DataType");
if ("xsd:string".equalsIgnoreCase(dataType.getLiteral()))
{
result[i] = OWL.dataFactory().getOWLLiteral("");
}
i++;
}
return result;
}
}
public static void main(String[] args) throws Exception
{
OWLWebServiceCall call = new OWLWebServiceCall(
individual("GarbageTruckRouteCheckService"));
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
//Document doc = builder.parse(new ByteArrayInputStream(
// "<hasPassed xmlns=\"sw\">no</hasPassed>".getBytes()));
//System.out
// .println(call.findNode(doc, "/sw:hasPassed").getTextContent());
Document doc = builder.parse(new ByteArrayInputStream(
"<XYAddressResponse xmlns=\"http://intra.miamidade.gov/GISAddress\"><XYAddressResult><Count>1</Count><XY><ArrXY><X>911075.00007005</X><Y>514594.87501394</Y><Zip_Code>33145</Zip_Code><Munic_Code>1</Munic_Code></ArrXY></XY></XYAddressResult></XYAddressResponse>".getBytes()));
//doc.s
Node node = call.findNode(doc, "/:XYAddressResponse/:XYAddressResult/:XY/:ArrXY[1]/:X");
System.out
.println(node.getTextContent());
}
}